#pragma once

#include <string>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

// 相关全局变量
const std::string gpathname = "mypipe";
const int gCreat = 1;
const int gUser = 2;
const int gMod = 0666;
const int gDefault = -1;
const int gBufferSize = 4096;

class namepipe
{
private:
    void CreatNamePipe(const std::string &pathname, int mod)
    {
        if (mkfifo(pathname.c_str(), mod)) // 创建命名管道
        {
            perror("mkfifo");
        }
    }
    void DestroyNamePipe()
    {
        if (unlink(_path_pipe) == -1) // 删除命名管道
        {
            perror("unlink");
        }
    }
    int OpenPipeWriteHeap()
    {
        int fd = open(_path_pipe, O_WRONLY); // 只写方式打开
        if (fd < 0)
        {
            perror("OpenPipeWrite->open"); // 只读方式打开
        }
        return fd;
    }

    int OpenPipeReadHeap()
    {
        int fd = open(_path_pipe, O_RDONLY);
        if (fd < 0)
        {
            perror("OpenPipeRead->open");
        }
        return fd;
    }

public:
    namepipe(const std::string &pathname, int who)
        : _path_pipe(pathname.c_str()), _who(who), _fd(gDefault)
    {
        if (_who == gCreat) // 如果是管理者就创建管道
            CreatNamePipe(pathname, gMod);
    }

    bool OpenPipeWrite() // 打开管道写端
    {
        _fd = OpenPipeWriteHeap(); // 相关调用
        if (_fd < 0)
            return false;
        return true;
    }

    bool OpenPipeRead() // 打开管道读端
    {
        _fd = OpenPipeReadHeap(); // 相关调用
        if (_fd < 0)
            return false;
        return true;
    }

    int DeliverMassage(const std::string &in) // 写端写入信息
    {
        return write(_fd, in.c_str(), in.size()); // 直接管道文件写
    }

    int GetMassage(std::string *out) // 读端获取信息
    {
        char buffer[gBufferSize];
        int n = read(_fd, buffer, gBufferSize); // 直接从管道文件中读
        if (n != 0)
        {
            buffer[n] = 0; // C语言字符串格式
            *out = buffer;
        }
        return n; // 返回读取字节的个数
    }

    ~namepipe()
    {
        if (_who == gCreat)
            DestroyNamePipe();
        if (_fd != gDefault)
            close(_fd);
    }

private:
    const char *_path_pipe; // 命名管道创建时所需的路径
    int _who;               // 身份标识
    int _fd;                // 命名管道的文件描述符
};